package au.com.koalaclass.config;

import au.com.koalaclass.dao.GatewayRouteDao;
import au.com.koalaclass.entity.FiltersEntity;
import au.com.koalaclass.entity.GatewayRouteEntity;
import au.com.koalaclass.entity.PredicatesEntity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.util.*;


/**
 * 核心配置类，项目初始化加载数据库的路由配置
 */
@Service
@Slf4j
public class GatewayServiceHandler implements ApplicationEventPublisherAware, CommandLineRunner {

    @Resource
    private RedisRouteDefinitionRepository routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    //自己的获取数据dao
    @Resource
    private GatewayRouteDao gatewayRouteDao;

    // springboot启动后执行
    @Override
    public void run(String... args) throws JsonProcessingException {
        this.loadRouteConfig();
    }

    /**
     * 加载路由
     *
     * @return
     * @throws JsonProcessingException
     */
    public String loadRouteConfig() {
        //从数据库拿到路由配置
        List<GatewayRouteEntity> gatewayRouteList = gatewayRouteDao.findAll();
        gatewayRouteList.forEach(gatewayRoute -> {
            RouteDefinition definition = handleData(gatewayRoute);
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        });

        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

    public void deleteRoute(String routeId) {
        routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    /**
     * 路由数据转换公共方法
     *
     * @param gatewayRoute
     * @return
     */
    private RouteDefinition handleData(GatewayRouteEntity gatewayRoute) {
        RouteDefinition definition = new RouteDefinition();
        URI uri = null;
        if (gatewayRoute.getUri().startsWith("http")) {
            //http地址
            uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();
        } else {
            //注册中心
            uri = UriComponentsBuilder.fromUriString("lb://" + gatewayRoute.getUri()).build().toUri();
        }

        definition.setId(gatewayRoute.getServiceId());

        //获取断言json字符串
        String predicates = gatewayRoute.getPredicates();
        // 获取过滤器json字符串
        String filters = gatewayRoute.getFilters();
        //获取数据库存储的断言信息、过滤器转成集合对象
        ObjectMapper mapper = new ObjectMapper();
        List<PredicatesEntity> predicatesArrayList = new ArrayList<>();
        List<FiltersEntity> filtersEntities = new ArrayList<>();
        try {
            predicatesArrayList = mapper.readValue(predicates, new TypeReference<List<PredicatesEntity>>() {
            });
            filtersEntities = mapper.readValue(filters, new TypeReference<List<FiltersEntity>>() {
            });
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        //循环拼装断言信息
        List<PredicateDefinition> predicateDefinitionList = new ArrayList<>();
        predicatesArrayList.forEach(predis -> {
            PredicateDefinition predicate = new PredicateDefinition();
            Map<String, String> predicateParams = new HashMap<>(8);
            // 名称是固定的，spring gateway会根据名称找对应的PredicateFactory
            predicate.setName(predis.getType());
            //判断断言有分号则进行拼接
            if (predis.getPredicates().indexOf(",") >= 0) {
                String[] pre = predis.getPredicates().split(",");
                for (int i = 0; i < pre.length; i++) {
                    predicateParams.put("_genkey_" + i,pre[i]);
                }
            } else {
                predicateParams.put("_genkey_0", predis.getPredicates());
            }
            predicate.setArgs(predicateParams);
            predicateDefinitionList.add(predicate);
        });

        //循环拼装过滤器信息
        List<FilterDefinition> filterDefinitionList = new ArrayList<>();
        filtersEntities.forEach(filter -> {
            // 名称是固定的, 路径去前缀
            FilterDefinition filterDefinition = new FilterDefinition();
            Map<String, String> filterParams = new HashMap<>(8);
            //设置过滤器名称
            filterDefinition.setName(filter.getType());
            //判断过滤器如果有逗号则进行分割
            if (filter.getRule().indexOf(",") >= 0) {
                String[] rules = filter.getRule().split(",");
                for (int i = 0; i < rules.length; i++) {
                    filterParams.put("_genkey_" + i,rules[i]);
                }
            } else {
                filterParams.put("_genkey_0", filter.getRule());
            }
            filterDefinition.setArgs(filterParams);
            filterDefinitionList.add(filterDefinition);
        });

        definition.setPredicates(predicateDefinitionList);
        definition.setFilters(filterDefinitionList);
        definition.setUri(uri);
        definition.setOrder(Integer.parseInt(gatewayRoute.getOrder()));

        return definition;
    }
}